package com.bfly.mall.wechat.service.impl;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.bfly.common.json.JsonUtil;
import com.bfly.core.base.service.BaseServiceImpl;
import com.bfly.core.enums.SysError;
import com.bfly.core.exception.ServiceResponseException;
import com.bfly.mall.wechat.dao.WeChatMpMenuMapper;
import com.bfly.mall.wechat.entity.WeChatMp;
import com.bfly.mall.wechat.entity.WeChatMpMaterial;
import com.bfly.mall.wechat.entity.WeChatMpMenu;
import com.bfly.mall.wechat.enums.WeChatMpMenuCategoryEnum;
import com.bfly.mall.wechat.mp.service.WeChatMPAPi;
import com.bfly.mall.wechat.service.IWeChatMpMaterialService;
import com.bfly.mall.wechat.service.IWeChatMpMenuService;
import com.bfly.mall.wechat.service.IWeChatMpService;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;

import java.util.*;

/**
 * @author 长沙商脉科技有限公司
 * @date 2021/1/4 14:31
 */
@Service
@Transactional(propagation = Propagation.SUPPORTS)
public class WeChatMpMenuServiceImpl extends BaseServiceImpl<com.bfly.mall.wechat.entity.WeChatMpMenu, Integer> implements IWeChatMpMenuService {

    @Autowired
    private WeChatMpMenuMapper weChatMpMenuMapper;
    @Autowired
    private IWeChatMpService weChatMpService;
    @Autowired
    private IWeChatMpMaterialService weChatMpMaterialService;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void merge(int platformId, JSONArray array) {
        WeChatMp mp = weChatMpService.get(platformId);
        if (mp == null) {
            throw new ServiceResponseException(SysError.PARAM_ERROR, "公众号信息不存在!");
        }
        checkMenu(array);
        List<WeChatMpMenu> menus = convert(platformId, array);
        // 先清空再保存
        weChatMpMenuMapper.clear();
        saveToDb(0, menus);
    }

    private void saveToDb(int parentId, List<WeChatMpMenu> menus) {
        if (menus != null) {
            for (WeChatMpMenu dto : menus) {
                if (dto == null) {
                    continue;
                }
                WeChatMpMenu menu = new WeChatMpMenu();
                BeanUtils.copyProperties(dto, menu);
                menu.setParentId(parentId);
                menu.setCreateDate(new Date());
                menu.setUpdateDate(new Date());
                super.save(menu);
                List<WeChatMpMenu> children = dto.getChildren();
                if (CollectionUtils.isNotEmpty(children)) {
                    saveToDb(menu.getId(), children);
                }
            }
        }
    }

    @Override
    public void pushMenuToWeChat(int platformId) {
        WeChatMp mp = weChatMpService.get(platformId);
        if (mp == null) {
            throw new ServiceResponseException(SysError.PARAM_ERROR, "公众号信息不存在!");
        }
        Map<String, Object> params = new HashMap<>();
        params.put("parent_id", 0);
        params.put("platform_id", platformId);
        List<WeChatMpMenu> list = getList(params);
        if (list == null || list.isEmpty()) {
            // 删除自定义菜单
            WeChatMPAPi.clearMenu(mp.getAppId(), mp.getAppSecret());
        } else {
            JSONArray array = convertForWeChat(list);
            JSONObject json = new JSONObject();
            json.put("button", array);
            WeChatMPAPi.createMenu(mp.getAppId(), mp.getAppSecret(), json);
        }
    }

    @Override
    public JSONArray getWeChatMenu(int platformId) {
        Map<String, Object> params = new HashMap<>();
        params.put("parent_id", 0);
        params.put("platform_id", platformId);
        List<WeChatMpMenu> list = getList(params);
        return convert(list);
    }

    /**
     * 不同类型的菜单验证
     *
     * @author 长沙商脉科技有限公司
     * @date 2021/1/6 15:35
     */
    private void checkMenu(JSONArray jsons) {
        try {
            for (Object object : jsons) {
                JSONObject json = (JSONObject) object;
                Assert.notNull(json, "数据不能为空!");
                int category = json.getInteger("category");
                String name = json.getString("name");
                Assert.hasText(name, "菜单名称不能为空!");
                WeChatMpMenuCategoryEnum categoryEnum = WeChatMpMenuCategoryEnum.getCategory(category);
                Assert.notNull(categoryEnum, "未知的菜单类型!");
                switch (categoryEnum) {
                    case LINK_WEB_MENU:
                        Assert.hasText(json.getString("webUrl"), "网页链接不能为空!");
                        break;
                    case OPEN_MINI_PRO_MENU:
                        Assert.hasText(json.getString("miniProUrl"), "小程序链接不能为空!");
                        Assert.hasText(json.getString("appId"), "小程序AppId不能为空!");
                        Assert.hasText(json.getString("pagePath"), "小程序页面路径不能为空!");
                        break;
                    case SEND_TEXT_MENU:
                        Assert.hasText(json.getString("content"), "内容不能为空!");
                        break;
                    case SEND_PIC_MENU:
                        Assert.hasText(json.getString("pictureMedia"), "图篇素材ID不能为空!");
                        break;
                    case SEND_NEWS_MENU:
                        Assert.hasText(json.getString("newsMedia"), "图文素材ID不能为空!");
                        Assert.hasText(json.getString("newsName"),"图文素材标题不能为空!");
                        break;
                    case SEND_VOICE_MENU:
                        Assert.hasText(json.getString("voiceMedia"), "语音素材ID不能为空!");
                        Assert.hasText(json.getString("voiceName"), "语音素材标题不能为空!");
                        break;
                    case SEND_VIDEO_MENU:
                        Assert.hasText(json.getString("videoMedia"), "视频素材ID不能为空!");
                        Assert.hasText(json.getString("videoName"), "视频素材标题不能为空!");
                        break;
                }
                checkMenu(json.getJSONArray("children"));
            }
        } catch (Exception e) {
            throw new ServiceResponseException(SysError.PARAM_ERROR, e.getMessage());
        }
    }

    /**
     * 转换为java对象
     *
     * @author 长沙商脉科技有限公司
     * @date 2021/1/6 22:27
     */
    private List<WeChatMpMenu> convert(int platformId, JSONArray jsons) {
        List<WeChatMpMenu> menus = new ArrayList<>();
        for (Object object : jsons) {
            JSONObject json = (JSONObject) object;
            WeChatMpMenu menu = new WeChatMpMenu();
            menu.setName(json.getString("name"));
            menu.setCategory(json.getInteger("category"));
            menu.setPlatformId(platformId);
            menu.setSeq(json.getInteger("seq"));

            int category = json.getInteger("category");
            WeChatMpMenuCategoryEnum categoryEnum = WeChatMpMenuCategoryEnum.getCategory(category);
            menu.setType(categoryEnum.getType());

            JSONObject dataJson = new JSONObject();
            switch (categoryEnum) {
                case LINK_WEB_MENU:
                    dataJson.put("webUrl", json.getString("webUrl"));
                    break;
                case OPEN_MINI_PRO_MENU:
                    dataJson.put("miniProUrl", json.getString("miniProUrl"));
                    dataJson.put("appId", json.getString("appId"));
                    dataJson.put("pagePath", json.getString("pagePath"));
                    break;
                case SEND_TEXT_MENU:
                    dataJson.put("content", json.getString("content"));
                    break;
                case SEND_PIC_MENU:
                    dataJson.put("pictureMedia", json.getString("pictureMedia"));
                    dataJson.put("pictureUrl", json.getString("pictureUrl"));
                    break;
                case SEND_NEWS_MENU:
                    dataJson.put("newsMedia", json.getString("newsMedia"));
                    dataJson.put("newsName", json.getString("newsName"));
                    break;
                case SEND_VOICE_MENU:
                    dataJson.put("voiceMedia", json.getString("voiceMedia"));
                    dataJson.put("voiceName", json.getString("voiceName"));
                    break;
                case SEND_VIDEO_MENU:
                    dataJson.put("videoMedia", json.getString("videoMedia"));
                    dataJson.put("videoName", json.getString("videoName"));
                    break;
            }

            menu.setData(dataJson.toJSONString());

            JSONArray children = json.getJSONArray("children");
            if (children != null && children.size() > 0) {
                List<WeChatMpMenu> childMenus = convert(platformId, children);
                menu.setChildren(childMenus);
            }
            menus.add(menu);
        }
        return menus;
    }

    /**
     * 转换为json对象
     *
     * @author 长沙商脉科技有限公司
     * @date 2021/1/7 14:02
     */
    private JSONArray convert(List<WeChatMpMenu> menus) {
        JSONArray array = new JSONArray();
        Collections.sort(menus);
        menus.forEach(menu -> {
            JSONObject json = new JSONObject();
            json.put("name", menu.getName());
            json.put("category", menu.getCategory());
            json.put("seq", menu.getSeq());

            JSONObject dataJson = JsonUtil.parse(menu.getData(), JSONObject.class);
            dataJson.forEach((s, o) -> json.put(s, o));
            List<WeChatMpMenu> children = menu.getChildren();
            if (children != null) {
                json.put("children", convert(children));
            }
            if(menu.getType().equalsIgnoreCase(WeChatMpMenuCategoryEnum.SEND_NEWS_MENU.getType())){
                // 关联的图文
                List<WeChatMpMaterial> newsMaterial = weChatMpMaterialService.getNewsMaterial(menu.getPlatformId(), dataJson.getString("newsMedia"));
                WeChatMpMaterial material=null;
                if(newsMaterial.size()>0) {
                    material = newsMaterial.get(0);
                    if (newsMaterial.size() > 1) {
                        material.setNews(newsMaterial.subList(1, newsMaterial.size() ));
                    }
                }
                json.put("news",material);
            }
            array.add(json);
        });
        return array;
    }

    /**
     * 转换微信公众号识别的json对象
     *
     * @author 长沙商脉科技有限公司
     * @date 2021/1/7 15:49
     */
    private JSONArray convertForWeChat(List<WeChatMpMenu> menus) {
        JSONArray array = new JSONArray();
        Collections.sort(menus);
        menus.forEach(menu -> {
            JSONObject json = new JSONObject();
            json.put("name", menu.getName());

            List<WeChatMpMenu> children = menu.getChildren();
            //如果有子菜单的主菜单不能有其他字段
            if (children == null || children.isEmpty()) {
                JSONObject dataJson = parseDataJson(menu);
                dataJson.forEach((s, o) -> json.put(s, o));
            } else {
                json.put("sub_button", convertForWeChat(children));
            }
            array.add(json);
        });
        return array;
    }

    private JSONObject parseDataJson(WeChatMpMenu menu) {
        WeChatMpMenuCategoryEnum categoryEnum = WeChatMpMenuCategoryEnum.getCategory(menu.getCategory());
        JSONObject json = new JSONObject();
        json.put("type", categoryEnum.getType());
        JSONObject dataJson = JsonUtil.parse(menu.getData(), JSONObject.class);
        switch (categoryEnum) {
            case LINK_WEB_MENU:
                json.put("url", dataJson.getString("webUrl"));
                break;
            case OPEN_MINI_PRO_MENU:
                json.put("url", dataJson.getString("miniProUrl"));
                json.put("appid", dataJson.getString("appId"));
                json.put("pagepath", dataJson.getString("pagePath"));
                break;
            default:
                // key 为固定头部标识+ 菜单ID，用于后面获取推送事件消息 判断菜单ID 反馈相应的配置内容
                json.put("key", categoryEnum.getKey() + "_" + menu.getId());
                break;
        }
        return json;
    }
}
